﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Mono.TextTemplating;
using Newtonsoft.Json;
using WHLRDF.Application.BLL;
using WHLRDF.Application.Model;
using WHLRDF.Code.Model;
using WHLRDF.ORM;

namespace WHLRDF.Code.BLL
{
    /// <summary>
    /// 代码生成器 方法
    /// </summary>
    public partial class DbCodeService
    {
        /// <summary>
        /// 通过模板生成文件
        /// </summary>
        /// <param name="tableId"></param>
        /// <param name="tempid"></param>
        /// <param name="strResult"></param>
        /// <returns></returns>
        public virtual bool CreateCode(string tableId, string templateid, ref string strResult)
        {
            Dictionary<string, string> dicCode = new Dictionary<string, string>();
            return this.CreateCode(tableId, templateid, ref strResult, ref dicCode);

        }

        /// <summary>
        /// 通过模板生成文件
        /// </summary>
        /// <param name="tableId">表id</param>
        /// <param name="templateid">模板id</param>
        /// <param name="strResult">返回字符串</param>
        /// <param name="dicCode">返回文件集合</param>
        /// <returns></returns>
        public virtual bool CreateCode(string tableId, string templateid, ref string strResult, ref Dictionary<string, string> dicCode)
        {
            if (string.IsNullOrWhiteSpace(tableId))
            {
                strResult = "参数错误";
                return false;
            }
            TemplateGenerator generator = new TemplateGenerator();
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(Uri).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(System.Linq.Enumerable).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(System.Reflection.Assembly).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(JsonConvert).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(JSONHelper).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(DbColumnEntity).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(UserEntity).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(UserService).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(CodeDomain).Assembly.Location));
            return CreateCode(generator, tableId.ToString(), templateid, ref strResult, ref dicCode);
        }

        /// <summary>
        /// 批量生成文件
        /// </summary>
        /// <param name="tableId"></param>
        /// <param name="templateid"></param>
        /// <param name="strError">错误信息</param>
        /// <param name="dicCode"></param>
        /// <returns></returns>
        public async Task<bool> CreateCodes(string tableId, string templateid, int round = 0, int maxRound = 0)
        {
            if (string.IsNullOrWhiteSpace(tableId))
            {
                return false;
            }
            string rootPath = ApplicationEnvironments.BaseDirectory + ApplicationEnvironments.TempPath + "code/";

            TemplateGenerator generator = new TemplateGenerator();
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(Uri).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(System.Linq.Enumerable).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(System.Reflection.Assembly).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(JsonConvert).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(JSONHelper).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(DbColumnEntity).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(UserEntity).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(UserService).Assembly.Location));
            generator.ReferencePaths.Add(Path.GetDirectoryName(typeof(CodeDomain).Assembly.Location));
            string[] tables = tableId.Split(new char[] { ',', ';' });
            if (tables != null && tables.Length > 0)
            {
                await Task.Factory.StartNew<bool>(() =>
                {
                    foreach (var tableid in tables)
                    {
                        if (!string.IsNullOrWhiteSpace(tableid))
                        {
                            string strResult = "";


                            var dicCode = new Dictionary<string, string>();
                            if (CreateCode(generator, tableid, templateid, ref strResult, ref dicCode))
                            {
                                if (dicCode != null && dicCode.Count > 0)
                                {
                                    foreach (var code in dicCode)
                                    {
                                        FileHelper.WriteLine(rootPath + code.Key, code.Value);
                                    }
                                }
                            }


                        }
                    }
                    if (maxRound == round)
                    {
                        if (Directory.Exists(rootPath))
                        {
                            if (File.Exists(ApplicationEnvironments.BaseDirectory + ApplicationEnvironments.TempPath + "code.zip"))
                            {
                                File.Delete(ApplicationEnvironments.BaseDirectory + ApplicationEnvironments.TempPath + "code.zip");
                            }
                            if (!Directory.Exists(ApplicationEnvironments.BaseDirectory + ApplicationEnvironments.TempPath))
                            {
                                Directory.CreateDirectory((ApplicationEnvironments.BaseDirectory + ApplicationEnvironments.TempPath).ToLower());
                            }
                            System.IO.Compression.ZipFile.CreateFromDirectory(rootPath,
                                (ApplicationEnvironments.BaseDirectory + ApplicationEnvironments.TempPath + "code.zip").ToLower(), System.IO.Compression.CompressionLevel.Optimal, true);
                            Directory.Delete(rootPath, true);
                        }

                    }
                    return true;
                });
            }
            return true;
        }

        /// <summary>
        /// 生成模板
        /// </summary>
        /// <param name="generator"></param>
        /// <param name="tableId"></param>
        /// <param name="templateid"></param>
        /// <param name="strResult"></param>
        /// <param name="dicCode"></param>
        /// <returns></returns>
        public bool CreateCode(TemplateGenerator generator, string tableId, string templateid, ref string strResult, ref Dictionary<string, string> dicCode)
        {
            Regex regexNamespace = new Regex("namespace\\s([a-zA-Z.]+.BLL|[a-zA-Z.]+.Model|[a-zA-Z.]+.Web.Controllers)");
            Dictionary<string, string> lstCreateCode = new Dictionary<string, string>();
            var tempEntity = this.GetById<DbTemplateEntity>(templateid);
            var tableEntity = this.GetById<DbTableEntity>(tableId);
            if (tempEntity == null || tableEntity == null)
            {
                strResult = "模板不存在";
                return false;
            }
            this.GetTemplate(tempEntity, lstCreateCode);
            CodeDomain domain = new CodeDomain(tableEntity);
            Regex regexClass = new Regex("\\s(I?" + domain.ClassName + "(Entity|Service|Map|Controller))");

            if (lstCreateCode != null && lstCreateCode.Count > 0)
            {
                string rootPath = tempEntity.Path.Substring(0, tempEntity.Path.IndexOf("/")) + "/";
                StringBuilder stringBuilder = new StringBuilder();
                foreach (var item in lstCreateCode)
                {
                    string outfile = "";
                    string outcontent = "";
                    generator.ProcessTemplate(null, item.Value.Replace("{0}", tableId.ToString()), ref outfile, out outcontent);
                    stringBuilder.Append(outcontent);
                    if (generator.Errors != null && generator.Errors.Count > 0)
                    {
                        strResult = generator.Errors.ToJson();
                        return true;
                    }
                    string nNamespace = "";
                    var matchNamespace = regexNamespace.Match(outcontent);
                    string path = "";
                    if (matchNamespace.Success)
                    {
                        nNamespace = matchNamespace.Groups[1].Value;
                    }
                    string className = "";
                    var regexClassMatch = regexClass.Match(outcontent);
                    if (regexClassMatch.Success)
                    {
                        className = regexClassMatch.Groups[1].Value;
                        path = rootPath + nNamespace + "/" + string.Format((item.Key.IndexOf("I") == 0 ? item.Key.Substring(1) : item.Key), domain.ClassName) + "/" + className + outfile;
                    }
                    if (!matchNamespace.Success)
                    {
                        nNamespace = "Views";
                        className = domain.ClassName;
                        path = rootPath + nNamespace + "/" + domain.ClassName + "/" + item.Key + outfile;
                    }
                    else
                    {
                        if (string.IsNullOrWhiteSpace(path))
                        {
                            path = rootPath + nNamespace + "/" + domain.ClassName + "/" + item.Key + outfile;
                        }
                    }
                    dicCode.Add(path, outcontent);
                }
                strResult = stringBuilder.ToString();
            }
            return true;
        }

        /// <summary>
        /// 获取可生成的模板列表
        /// </summary>
        /// <param name="tempEntity">上级模板id</param>
        /// <param name="lstCreateCode">需要生成的模板集合</param>
        public void GetTemplate(DbTemplateEntity tempEntity, Dictionary<string, string> lstCreateCode)
        {
            string templateLine = "";
            var lstTemp = this.Query<DbTemplateEntity>(Expression.And(Expression.Eq(DbTemplateEntity.__IsDeleted, 0), Expression.Eq(DbTemplateEntity.__ParentId, tempEntity.TemplateId)));
            if (lstTemp != null && lstTemp.Count > 0)
            {
                foreach (var item in lstTemp)
                {

                    var children = this.Query<DbTemplateEntity>(Expression.And(Expression.Eq(DbTemplateEntity.__IsDeleted, 0), Expression.Eq(DbTemplateEntity.__ParentId, item.TemplateId)));
                    if (children != null && children.Count > 0)
                    {
                        foreach (var citem in children)
                        {
                            templateLine = FileHelper.ReadLine((DbTemplateService.RootPath + citem.Path + citem.TemplateName + ".tt").ToLower());
                            if (!string.IsNullOrWhiteSpace(templateLine))
                            {
                                lstCreateCode.Add(citem.TemplateName, templateLine);
                            }
                        }
                    }
                    templateLine = FileHelper.ReadLine((DbTemplateService.RootPath + item.Path + item.TemplateName + ".tt").ToLower());
                    if (!string.IsNullOrWhiteSpace(templateLine))
                    {
                        lstCreateCode.Add(item.TemplateName, templateLine);
                    }
                }
            }
            templateLine = FileHelper.ReadLine((DbTemplateService.RootPath + tempEntity.Path + tempEntity.TemplateName + ".tt").ToLower());
            if (!string.IsNullOrWhiteSpace(templateLine))
            {
                lstCreateCode.Add(tempEntity.TemplateName, templateLine);
            }
        }
    }
}
